#!/usr/bin/perl -w
# File: send_new_config_file.pl
# Usage: send_new_config_file.pl -f [file_name]
# Author: Tao Zhang


use strict;
use warnings;
use POSIX qw(:signal_h);
use Proc::Daemon;
use IO::Socket;
use Digest::MD5;
use MLUtils::Logger qw(mllogerr);
use Getopt::Long;
use File::Basename;

my $script_name = "send_new_config_file.pl";
my $dir = "/home/t0612z/workspace";
my $file_name = undef;
my $file_md5 = undef;
my $timeout = 10;

# -------------------subroutines----------------------------

sub usage() {
    print "Usage: Arguments format is not correct!\n";
    print "Correct Usage:\n\n";
    print "$script_name -f <file_name> \n";
}

sub checksum($) {
    my $file = shift;
    my $md5 = Digest::MD5->new();
    
    open(FL, "$dir/$file") 
        or die "Failed to open $file for MD5 checksum. \n";
    binmode(FL);
    my $md5sum = $md5->addfile(*FL)->hexdigest; 
    close FL;
    
    return $md5sum;
}

sub compare_ctlstr($$) {
    my $server = shift;
    my $ctrstr = shift;
    my $found = 0;
    chomp($ctrstr);
    
    eval {
        local $SIG{'ALRM'} = sub { die "Timed out" };
        alarm($timeout);
        my $input = <$server>;
        chomp($input);
        if ($input =~ /$ctrstr/) {
            $found = 1;
        } else {
            $found = 0;
        }
        alarm(0);
    };
    if ($@ =~ /Timed out/) {
        print STDERR "Waitting for $ctrstr timed Out.\n";
        $server->close();
        exit -1;
    }
    
    return $found;
}

sub wait_for_ctrstr($) {
    my $server = shift;
    my $input = undef;
    
    eval {
        local $SIG{'ALRM'} = sub { die "Timed out" };
        alarm($timeout);
        $input = <$server>;
        alarm(0);
    };
    
    if ($@ =~ /Timed out/) {
        print STDERR "Waitting for control string timed Out.\n";
        $server->close();
        exit -1;
    }
    
    if ($input) {
        return $input;
    } else {
        print STDERR "Failed to read from client.\n";
        $server->close();
        exit -1;
    }
}

sub send_file($) {
    my $server = shift;

    # send file content
    if ( ! open(CFG,"<$dir/$file_name") ) {
        print STDERR "Failed to open $file_name!\n";
        print $server "MLTRAN:QUIT\n";
        close $server;
        exit -1;
    }

    while ( my $content = <CFG> ) {
        print $server $content;
    }

    # send EOF flag
    print $server "MLTRAN:EOF\n";
}

# -----------------------main----------------------------
GetOptions('f=s' => \$file_name,);
if ( ! $file_name ) {
    usage();
    exit -1;
}

if ( ! -e "$dir/$file_name" ) {
    print STDERR "Failed to find $file_name!\n";
    exit -1;
}

if ( ! ($file_md5 = checksum($file_name)) ) {
    print STDERR "Failed to get the checksum for $file_name.\n";
    exit -1;
}

my $server = IO::Socket::INET->new(
    PeerAddr => '10.10.0.203',
    PeerPort => 8000,
    Proto    => 'tcp'
) or die "Can't create client socket: $!";

$server->autoflush(1);

# send transaction mode
print $server "MLTRAN:FILE:$file_name:$file_md5\n";

# wait for start flag
if ( ! compare_ctlstr($server, "MLTRAN:WAIT") ) {
    print STDERR "Failed to receive MLWAIT from server.\n";
    $server->close();
    exit -1;
}

my $repeat = 1;
while ($repeat) {
    # send file 
    send_file($server);
    
    my $flag = wait_for_ctrstr($server);
    if ( $flag =~ "MLTRAN:SUCC" ) {
        print $server "MLTRAN:QUIT\n";
        select(undef,undef,undef,0.25);
        $server->close();
        $repeat = 0;
    } elsif ( $flag =~ "MLTRAN:NOMORETRY" ) {
         print $server "MLTRAN:QUIT\n";
         select(undef,undef,undef,0.25);
         $server->close();
         print STDERR "Failed to get integrity flag.\n";
         exit -1;
    } 
}
exit 0;

